﻿namespace FiftyOne
{
    using System;
    using System.Collections.Generic;
    using System.Reflection;
    using System.Runtime.InteropServices;
    using System.Threading;

    internal class Cache<Key, Value>
    {
        private Dictionary<Key, Value> _internalCache;
        private Dictionary<Key, DateTime> _lastAccessed;
        private static DateTime _nextServiceTime;
        private int _timeout;

        static Cache()
        {
            Cache<Key, Value>._nextServiceTime = DateTime.MinValue;
        }

        internal Cache(int timeout)
        {
            this._internalCache = null;
            this._lastAccessed = null;
            this._timeout = 0;
            this._internalCache = new Dictionary<Key, Value>();
            this._lastAccessed = new Dictionary<Key, DateTime>();
            this._timeout = timeout;
        }

        private void CheckIfServiceRequired()
        {
            if ((Cache<Key, Value>._nextServiceTime < DateTime.UtcNow) && (this._internalCache.Count > 0))
            {
                Cache<Key, Value>._nextServiceTime = DateTime.MaxValue;
                ThreadPool.QueueUserWorkItem(new WaitCallback(this.ServiceCache), DateTime.UtcNow.AddMinutes((double) -this._timeout));
            }
        }

        protected internal bool Contains(Key key)
        {
            bool flag = false;
            if (key != null)
            {
                lock (((Cache<Key, Value>) this))
                {
                    flag = this._internalCache.ContainsKey(key);
                    if (flag)
                    {
                        this._lastAccessed[key] = DateTime.UtcNow;
                    }
                }
            }
            return flag;
        }

        protected internal bool GetTryParse(Key key, out Value value)
        {
            bool flag = false;
            if (key != null)
            {
                lock (((Cache<Key, Value>) this))
                {
                    flag = this._internalCache.TryGetValue(key, out value);
                    if (flag)
                    {
                        this._lastAccessed[key] = DateTime.UtcNow;
                    }
                }
            }
            else
            {
                value = default(Value);
            }
            this.CheckIfServiceRequired();
            return flag;
        }

        protected internal void Remove(Key key)
        {
            if (this._internalCache.ContainsKey(key))
            {
                this._internalCache.Remove(key);
            }
        }

        private void ServiceCache(object purgeDate)
        {
            Key current;
            Cache<Key, Value> cache;
            Queue<Key> queue = new Queue<Key>();
            lock ((cache = (Cache<Key, Value>) this))
            {
                using (Dictionary<Key, DateTime>.KeyCollection.Enumerator enumerator = this._lastAccessed.Keys.GetEnumerator())
                {
                    while (enumerator.MoveNext())
                    {
                        current = enumerator.Current;
                        if (this._lastAccessed[current] < ((DateTime) purgeDate))
                        {
                            queue.Enqueue(current);
                        }
                    }
                }
            }
            if (queue.Count > 0)
            {
                while (queue.Count > 0)
                {
                    current = queue.Dequeue();
                    if (current != null)
                    {
                        lock ((cache = (Cache<Key, Value>) this))
                        {
                            if (this._lastAccessed[current] < ((DateTime) purgeDate))
                            {
                                this._lastAccessed.Remove(current);
                                this._internalCache.Remove(current);
                            }
                        }
                    }
                }
                GC.Collect();
            }
            Cache<Key, Value>._nextServiceTime = DateTime.UtcNow.AddMinutes(1.0);
        }

        protected internal Value this[Key key]
        {
            get
            {
                Value local;
                lock (((Cache<Key, Value>) this))
                {
                    if (this._internalCache.TryGetValue(key, out local))
                    {
                        this._lastAccessed[key] = DateTime.UtcNow;
                    }
                }
                this.CheckIfServiceRequired();
                return local;
            }
            set
            {
                lock (((Cache<Key, Value>) this))
                {
                    if (this.Contains(key))
                    {
                        this._internalCache[key] = value;
                    }
                    else
                    {
                        this._internalCache.Add(key, value);
                        this._lastAccessed[key] = DateTime.UtcNow;
                    }
                }
            }
        }
    }
}

